QPY: Bug fix in Rust implementation of SparsePauliObservableElemPack - #16788
QPY: Bug fix in Rust implementation of SparsePauliObservableElemPack#16788gadial wants to merge 2 commits into
SparsePauliObservableElemPack#16788Conversation
Coverage Report for CI Build 32117132256Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage increased (+0.04%) to 87.818%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions11 previously-covered lines in 3 files lost coverage.
Coverage Stats
💛 - Coveralls |
|
One or more of the following people are relevant to this code:
|
| pub struct SparsePauliObservableElemPack { | ||
| pub num_qubits: u32, | ||
| #[bw(calc = coeff_data.len() as u64)] | ||
| #[bw(calc = (coeff_data.len() * std::mem::size_of::<f64>()) as u64)] |
There was a problem hiding this comment.
Aren't the coeffs Complex64? Or why is f64 the correct size?
There was a problem hiding this comment.
Look at _write_elem_sparse in the python code (the source of the format, in this case). coeffs are stored using
coeff_data = struct.pack(
f"!{len(coeffs)*2}d", *(val for coeff in coeffs for val in (coeff.real, coeff.imag))
)
So each coeff is stored using two consecutive f64 values comprising the original Complex64.
In the rust code we do the same, on pack_sparse_pauli_op:
let coeff_data = sparse_observable
.coeffs()
.iter()
.flat_map(|coeff| [coeff.re, coeff.im])
.collect();
| #[bw(calc = (coeff_data.len() * std::mem::size_of::<f64>()) as u64)] | ||
| pub coeff_data_size: u64, | ||
| #[bw(calc = bitterm_data.len() as u64)] | ||
| #[bw(calc = (bitterm_data.len() * std::mem::size_of::<u16>()) as u64)] |
There was a problem hiding this comment.
I think there's something I'm not understanding, I thought this would correspond to the size of BitTerm which is u8 -- could you explain where these sizes are coming from?
There was a problem hiding this comment.
This is a bug in the original python implementation, and is actually one of the things we're gonna fix in QPY18, you can see it on the list at #15524. Even more, this bug was found as part of the fix...
The python code used bitterm_data = struct.pack(f"!{len(bitterms)}H", *bitterms); instead of H it should have been a B.
Summary
Fixes a bug in the way Rust QPY serializes and deserializes
SparsePauliObservableElemPack.Fixes #16722
Details
When serializing
SparsePauliObservableElemPack, there are several lists of elements being serialized. While Rust stored the lengths of the lists, Python stored the actual sizes of the serialized lists. It is possible to make sure Rust conforms to this serialization by dividing and multiplying by the correct factors (dependent on the known sizes of the stored elements).AI/LLM disclosure